/*
 *
 * Copyright (C) 2008 Jose Javier García Zornoza.
 * 
 * Este es un programa libre; puedes distribuirlo y/o modificarlo bajo
 * los términos de la versión 2 (o cualquier versión posterior) de la Licencia 
 * Pública General de la Fundación de Software Libre.
 * Este programa se distribuye con la esperanza  de poder ser útil, pero sin
 * NINGUNA GARANTIA; tampoco la garantía implícita de COMERCIALIZACION o DEDICACIÓN
 * A UN PROPOSITO PARTICULAR. Ver la licencia GNU GPL para más detalles.
 * Deberías haber recibido una copia de la licencia GNU GPL con este programa;
 * en caso contrario puedes obtener una copia visitando el sitio web www.fsf.org
 * o escribiendo a la Fundación de Software Libre, Inc., 59 Temple 
 * Place - Suite 330, Boston, MA  02111-1307, USA. 
 *
 */
package org.gruposp2p.dnie.crypto;

import org.gruposp2p.dnie.xml.validation.SchemaValidator;
import java.io.File;
import java.security.PublicKey;
import java.security.cert.X509Certificate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.xml.security.keys.KeyInfo;
import org.apache.xml.security.signature.XMLSignature;
import org.apache.xml.security.utils.Constants;
import org.apache.xml.security.utils.XMLUtils;
import org.apache.xpath.XPathAPI;
import org.gruposp2p.dnie.utils.XmlUtils;
import org.gruposp2p.dnie.utils.OfflineResolver;
import org.w3c.dom.Element;
import org.w3c.dom.Document;

public class SignatureValidator {

    private static Logger logger = LoggerFactory.getLogger(SignatureValidator.class);
   
    static { org.apache.xml.security.Init.init(); }

    private X509Certificate certificate;

    public SignatureValidator () {}

    public boolean validateSignature (File file, boolean withSchemaValidation)
            throws Exception {
        javax.xml.parsers.DocumentBuilderFactory dbf =
        javax.xml.parsers.DocumentBuilderFactory.newInstance();
        dbf.setNamespaceAware(true);
        dbf.setAttribute("http://xml.org/sax/features/namespaces", Boolean.TRUE);
        javax.xml.parsers.DocumentBuilder db = dbf.newDocumentBuilder();
        db.setErrorHandler(new org.apache.xml.security.utils
            .IgnoreAllErrorHandler());
        Document doc = db.parse(new java.io.FileInputStream(file));
        return validateSignature(doc, withSchemaValidation);
    }
    
    public boolean validateSignature (String mensaje, boolean validacionSchema)
            throws Exception {
        return validateSignature (
                XmlUtils.getDocumentFromString(mensaje, true), validacionSchema);
    }
    
    public boolean validateSignature (Document doc, boolean validacionSchema)
            throws Exception {
        if (validacionSchema) {
            SchemaValidator validadora = new SchemaValidator();
            validadora.validarSchema(doc);
        }
        boolean resultadoValidacion = false;
        Element nscontext = XMLUtils.createDSctx(doc, "ds",
                                      Constants.SignatureSpecNS);
        Element sigElement = (Element) XPathAPI.selectSingleNode(doc,
                     "//ds:Signature[1]", nscontext);
        XMLSignature signature = new XMLSignature(sigElement,"");
        signature.addResourceResolver(new OfflineResolver());
        // XMLUtils.outputDOMc14nWithComments(signature.getElement(), System.out);
        KeyInfo ki = signature.getKeyInfo();
        if (ki == null) throw new Exception ("El documento no tiene objeto KeyInfo");
        certificate = signature.getKeyInfo().getX509Certificate();
        if (getCertificate() != null) {
            resultadoValidacion = signature.checkSignatureValue(getCertificate());
        } else {
            PublicKey publicKey = signature.getKeyInfo().getPublicKey();
            if (publicKey != null) {
                resultadoValidacion = signature.checkSignatureValue(publicKey);
            } else {
                throw new Exception (
                        "No se ha encontrado ni certificaod ni clave pública en el documento");
            }
        }        
        return resultadoValidacion;
    }

    public X509Certificate getCertificate() {
        return certificate;
    }
}
